using UnityEngine;
using System.Collections;

public class Inventory {
	public const int NUM_ROWS = 4;
	public const int NUM_COLS = 5;
	
	int num_rows_int;
	int num_cols_int;
	ItemStack[] items;
	
	/* needs to be a property to handle resizing */
	public int NumRows {
		set {
			this.num_rows_int = value;
		}
		
		get {
			return num_rows_int;
		}
	}
	
	/* needs to be a property to handle resizing */
	public int NumCols {
		set {
			this.num_cols_int = value;
		}
		
		get {
			return num_cols_int;
		}
	}
	
	public Inventory(
		int rows=Inventory.NUM_ROWS,
		int cols=Inventory.NUM_COLS) {
		this.NumRows = rows;
		this.NumCols = cols;
		
		this.items = new ItemStack[this.NumRows*this.NumCols];
	}
	
	private int GetItemIndex(int row, int col) {
		return col + (this.NumCols*row);
	}
	
	public bool HasSpaceForItemStack(ItemStack s) {
		bool is_stackable;
		int amount;
		
		is_stackable = s.item.IsStackable();
		amount = s.amount;
		
		foreach (ItemStack curr in this.items) {
			if (curr == null) {
				/* empty slot, so there's room */
				return true;
			}
			
			if (is_stackable && Item.CompareItemType(curr.item, s.item)) {
				if (amount <= curr.FreeCapacity()) {
					return true;
				} else {
					amount -= curr.FreeCapacity ();
				}
			}
		}
		
		return (amount == 0);
	}
	
	/**
	 * TODO: maybe throw some exceptions if we can't add it
	 * @param simulate: true if we don't want to actually do the action
	 */
	public bool AddItemStack(ItemStack s) {
		int index = 0;
		bool slot_found = false;
		
		/* stackable case */
		if (s.item.IsStackable ()) {		
			/* Find the first item like it */
			foreach (ItemStack curr in this.items) {
				if (curr == null) {
					continue;
				}
				
				if (Item.CompareItemType(curr.item, s.item)) {
					curr.TakeAllFrom(s);
					if (s.amount == 0) {
						return true;
					}
				}
			}
		}
		
		index = 0;
		foreach (ItemStack curr in this.items) {
			if (curr == null) {
				slot_found = true;
				this.items[index] = s;
				break;
			}
			index++;
		}
		
		return slot_found;
	}
	
	public ItemStack GetItemStack(int row, int col) {
		return this.items[this.GetItemIndex (row, col)];
	}
	
	public bool AddItemStack(ItemStack s, int row, int col, bool allow_overflow=true) {
		int index;
		
		if ((row >= this.NumRows) || (col >= this.NumCols)) {
			return false;
		}
		
		index = this.GetItemIndex(row, col);
		if (this.items[index] != null) {
			if (allow_overflow && s.item.IsStackable()) {
				this.items[index].TakeAllFrom(s);
				
				return AddItemStack(s);
			} else {
				return false;
			} 
		} else {
			this.items[index] = s;
		}
		
		return true;
	}
	
	public ItemStack RemoveItemStack(int row, int col) {
		int index;
		ItemStack s;
		
		index = this.GetItemIndex(row, col);
		
		s = this.items[index];
		this.items[index] = null;
		
		return s;
	}
	
	public bool MoveItemStack(
		int src_row, int src_col,
		int dst_row, int dst_col) {
		ItemStack src;
		ItemStack dst;
		
		src = this.GetItemStack(src_row, src_col);
		if (src == null) {
			/* nothing to do if src is an empty stack */
			return false;
		}
		
		dst = this.GetItemStack (dst_row, dst_col);
		if (dst == null) {
			/* Move src into dst's spot */
			this.RemoveItemStack (src_row, src_col);
			return this.AddItemStack (src, dst_row, dst_col, allow_overflow : false);
		}
		
		/* src and dst are both not null */
		if (Item.CompareItemType(src.item, dst.item) &&
			src.item.IsStackable () &&
			dst.item.IsStackable ()) {
			/* move as much of src into dst as possible */
			dst.TakeAllFrom(src);
			if (src.amount == 0) {
				this.RemoveItemStack(src_row, src_col);
			}
		} else {
			/* cannot merge, so swap places */			
			this.RemoveItemStack (src_row, src_col);
			this.AddItemStack (dst, src_row, src_col, allow_overflow : false);
			
			this.RemoveItemStack(dst_row, dst_col);
			this.AddItemStack (src, dst_row, dst_col, allow_overflow : false);
			
		}
		
		return true;
	}
}
